﻿using System;
using System.Windows;
using System.Windows.Threading;
using System.Windows.Forms;

namespace Domotica.Gazing.Calibration
{

    internal class Calibrator
    {
        public Calibrator(Config config)
        {
            _Config = config;
        }

        private int _Current;
        private CalibrationWindow _Window;
        private ProcessorList _Processors;

        private CalibratorScreenList _ScreenList;
        private CalibrationState _State;
        private bool _Started;
        private readonly Config _Config;
        private DispatcherTimer _Timer;

        public Config Config
        {
            get { return _Config; }
        }

        public bool Calibrated
        {
            get { return _Config.Calibrated; }
        }

        public CalibrationState State
        {
            get { return _State; }
        }

        public CalibratorScreenList ScreenList
        {
            get { return _ScreenList; }
        }

        public void Start()
        {
            if (_Started)
            {
                return;
            }

            MakeScreenList();

            _Window = new CalibrationWindow();
            _Window.Show();

            _Timer = new DispatcherTimer();
            _Timer.Interval = TimeSpan.FromMilliseconds(50);

            _Timer.Tick += Process;

            _Timer.Start();

            _State = CalibrationState.Smoothing;
            _Processors
                = new ProcessorList
                      {
                          new ScreensProcessor(this),
                          new SmoothingProcessor(this)
                      };
            _Started = true;
        }

        public void Quick()
        {
            if (_Started)
            {
                return;
            }

            MakeScreenList();

            _Window = new CalibrationWindow();
            _Window.Show();

            _Timer = new DispatcherTimer();
            _Timer.Interval = TimeSpan.FromMilliseconds(50);

            _Timer.Tick += Process;

            _Timer.Start();

            _State = CalibrationState.Smoothing;
            _Processors
                = new ProcessorList
                      {
                          new QuickProcessor(this)
                      };
            _Started = true;
        }

        private void Finish()
        {
            if (_Window != null)
                _Window.Hide();
            if (_Timer != null)
                _Timer.Stop();
            _Config.Calibrated = true;
        }

        public void Process(object sender, EventArgs e)
        {
            if (_Current >= _Processors.Count)
            {
                Finish();
                return;
            }

            if (_Processors[_Current].Process())
            {
                _Current += 1;
            }
        }

        public void OnFaceMove(GazeEventArgs e)
        {
            if (Calibrated || 
                _Current >= _Processors.Count)
            {
                return;
            }
            _Processors[_Current].OnFaceMove(e);
        }

        public void OnGazeClick(GazeClickEventArgs e)
        {
            if (Calibrated ||
                _Current >= _Processors.Count)
            {
                return;
            }
            _Processors[_Current].OnGazeClick(e);
        }

        private void MakeScreenList()
        {
            _ScreenList = new CalibratorScreenList();
            Screen[] screens = Screen.AllScreens;
            for (int i = 0; i < screens.Length; i++)
            {
                _ScreenList.Add(new CalibratorScreen(i, screens[i]));
            }
        }

        public void OnGazeClickedElapsed(GazeClickElapsedEventArgs e)
        {
            if (Calibrated ||
                _Current >= _Processors.Count)
            {
                return;
            }
            _Processors[_Current].OnGazeClickElapsed(e);

        }

        #region Form

        public void FormSetLocation(Point position)
        {
                _Window.Left = position.X;
                _Window.Top = position.Y;
        }

        public void FormSetTopText(string text)
        {
                _Window.SetTopText(text);
        }

        public void FormSetMiddleText(string text)
        {
                _Window.SetMiddleText(text);
        }

        public void FormSetBottomText(string text)
        {
                _Window.SetBottomText(text);
        }

        public void FormHide()
        {
                _Window.Hide();
        }

        public void FormShow()
        {
                _Window.Show();
        }

        internal Point FormGetLocation()
        {
                return  new Point((int)_Window.Left, (int)_Window.Top);
        }

        internal Size FormGetSize()
        {
                return new Size((int)_Window.Width, (int)_Window.Height);
        }

        #endregion

        public void Stop()
        {
            Finish();
            if (_Window != null)
                _Window.Close();
        }
    }
}